package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.common.constants.article.ArticleConstants;
import com.heima.common.constants.article.HotArticleConstants;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.mess.ArticleVisitStreamMess;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @作者 itcast
 * @创建日期 2020/9/27 10:13
 **/
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    // 单页最大加载数
    private final static short MAX_PAGE_SIZE = 50;

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Value("${fdfs.url}")
    private String fileServerUrl;

    @Override
    public ResponseResult load(Short loadType, ArticleHomeDto dto) {
        // 1. 校验参数
        Integer size = dto.getSize();
        if(size==null||size==0){
            size=10;
        }
        size = Math.min(size,MAX_PAGE_SIZE);
        dto.setSize(size);
        // 参数类型检验 loadType必须是 1 或 2
        if(!loadType.equals(ArticleConstants.LOADTYPE_LOAD_MORE)&&!loadType.equals(ArticleConstants.LOADTYPE_LOAD_NEW)){
            loadType = ArticleConstants.LOADTYPE_LOAD_MORE;
        }
        // 文章频道校验
        if(StringUtils.isEmpty(dto.getTag())){
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }
        // 时间校验
        if(dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        // 2. 查询数据
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, loadType);
        // 3. 结果封装
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }

    @Override
    public ResponseResult load2(Short loadType, ArticleHomeDto dto, boolean firstPage) {
        if (firstPage){
            // 从redis中获取缓存数据
            String jsonStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + dto.getTag());
            if(StringUtils.isNotEmpty(jsonStr)){ // 缓存不为空 返回缓存数据
                List<HotArticleVo> hotArticleVoList = JSON.parseArray(jsonStr, HotArticleVo.class);
                if(!hotArticleVoList.isEmpty()&& hotArticleVoList.size() > 0){
                    ResponseResult responseResult = ResponseResult.okResult(hotArticleVoList);
                    responseResult.setHost(fileServerUrl);
                    return responseResult;
                }
            }
        }
        return load(loadType,dto);
    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 重新计算文章分值
     * @param mess
     */
    @Override
    public void updateApArticle(ArticleVisitStreamMess mess) {
        // 1. 查询文章数据
        ApArticle apArticle = getById(mess.getArticleId());
        // 2. 修改文章
        apArticle.setViews((int)(apArticle.getViews()==null ? mess.getView() : apArticle.getViews() + mess.getView()));
        apArticle.setCollection((int)(apArticle.getCollection()==null ? mess.getCollect() : apArticle.getCollection() +mess.getCollect()));
        apArticle.setComment((int)(apArticle.getComment()==null ? mess.getComment() : apArticle.getComment() +mess.getComment()));
        apArticle.setLikes((int)(apArticle.getLikes()==null ? mess.getLike() : apArticle.getLikes() +mess.getLike()));
        updateById(apArticle);
        // 3. 计算文章的分值
        Integer score = computeScore(apArticle);
        score = score*3; // 今日热点文章热度X3
        HotArticleVo hotArticleVo = new HotArticleVo();
        BeanUtils.copyProperties(apArticle,hotArticleVo);
        hotArticleVo.setScore(score);
        // 4. 更新对应频道redis缓存
        String articleListStr = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId());
        List<HotArticleVo> hotArticleVoList = getHotArticleVos(hotArticleVo, articleListStr);
        redisTemplate.opsForValue().set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + apArticle.getChannelId(), JSON.toJSONString(hotArticleVoList));
        // 5. 更新推荐频道redis缓存
        String articleListStr2 = redisTemplate.opsForValue().get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
        List<HotArticleVo> hotArticleVoList2 = getHotArticleVos(hotArticleVo, articleListStr2);
        redisTemplate.opsForValue().set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG, JSON.toJSONString(hotArticleVoList2));
    }

    /**
     * 获取热点文章列表
     * @param hotArticleVo
     * @param articleListStr
     * @return
     */
    private List<HotArticleVo> getHotArticleVos(HotArticleVo hotArticleVo, String articleListStr) {
        List<HotArticleVo> hotArticleVoList = null;
        if(StringUtils.isNotEmpty(articleListStr)){
            hotArticleVoList = JSONArray.parseArray(articleListStr, HotArticleVo.class);
            // 如果热点文章列表中已经包含的话 替换
            boolean notHas = true;
            for (HotArticleVo articleVo : hotArticleVoList) {
                if(articleVo.getId().equals(hotArticleVo.getId())){
                    articleVo.setScore(hotArticleVo.getScore());
                    notHas = false;
                    break;
                }
            }
            // 如果不包含 加入到热点文章列表中 然后进行热度降序 取前30个热点文章
            if(notHas){
                hotArticleVoList.add(hotArticleVo);
            }
            hotArticleVoList = hotArticleVoList.stream()
                    .sorted((o1,o2)-> o2.getScore().compareTo(o1.getScore()))
                    .limit(30)
                    .collect(Collectors.toList());
            // 将对应频道的热点数据存入到缓存
        }
        return hotArticleVoList;
    }

    /**
     * 重新计算文章分析,并替换分值
     * @param apArticle
     * @return
     */
    private Integer computeScore(ApArticle apArticle) {
        Integer score = 0;
        if (apArticle.getViews()!=null) {
            score +=apArticle.getViews()+score;
        }
        if (apArticle.getLikes()!=null) {
            score +=apArticle.getLikes()*ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT  +score;
        }
        if (apArticle.getComment()!=null) {
            score +=apArticle.getComment()*ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT+score;
        }
        if (apArticle.getCollection()!=null) {
            score +=apArticle.getCollection()*ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT+score;
        }
        return score;
    }
}
